﻿using System;
using System.Drawing;
using Styx;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Helpers;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace TheFinalCall
{
    public partial class TheFinalCallRoutine : CombatRoutine
    {
        private static ulong _guidLastTarget;

        public TheFinalCallRoutine()
        {
            Instance = this;

            // Do this now, so we ensure we update our context when needed.
            BotEvents.Player.OnMapChanged += e =>
                {
                    // Don't run this handler if we're not the current routine!
                    if (RoutineManager.Current.Name != Name)
                        return;

                    // Only ever update the context. All our internal handlers will use the context changed event
                    // so we're not reliant on anything outside of ourselves for updates.
                    UpdateContext();
                };

            // install botevent handler so we can consolidate validation on whether 
            // .. local botevent handlers should be called or not
            TheFinalCallBotEventInitialize();
        }

        public static TheFinalCallRoutine Instance { get; private set; }

        public override string Name
        {
            get { return "TheFinalCall"; }
        }

        public override WoWClass Class
        {
            get { return WoWClass.Druid; }
        }

        public override bool WantButton
        {
            get { return false; }
        }

        private static LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }

        private static bool IsMounted
        {
            get
            {
                switch (StyxWoW.Me.Shapeshift)
                {
                    case ShapeshiftForm.FlightForm:
                    case ShapeshiftForm.EpicFlightForm:
                        return true;
                }
                return StyxWoW.Me.Mounted;
            }
        }

        //TODO: TIME FOR CONFIG OVA HERE
        /*private ConfigurationForm _configForm;
        public override void OnButtonPress()
        {
            if (_configForm == null || _configForm.IsDisposed || _configForm.Disposing)
                _configForm = new ConfigurationForm();

            _configForm.Show();
        }*/

        public override void Pulse()
        {
            // No pulsing if we're loading or out of the game.
            if (!StyxWoW.IsInGame || !StyxWoW.IsInWorld)
                return;

            // Update the current context, check if we need to rebuild any behaviors.
            UpdateContext();

            // Double cast shit
            Spell.DoubleCastPreventionDict.RemoveAll(t => DateTime.UtcNow.Subtract(t).TotalMilliseconds >= 2500);
            if (Group.MeIsTank && CurrentWoWContext != WoWContext.Battlegrounds &&
                (Me.GroupInfo.IsInParty || Me.GroupInfo.IsInRaid))
                TankManager.Instance.Pulse();

            HotkeyManager.Pulse();
        }

        public override void Initialize()
        {
            WriteSupportInfo();

            Logger.Write("Determining talent spec.");
            try
            {
                TalentManager.Update();
            }
            catch (Exception e)
            {
                StopBot(e.ToString());
            }
            Logger.Write("Current spec is " + TalentManager.CurrentSpec.ToString().CamelToSpaced());

            // write current settings to log file... only written at startup and when Save press in Settings UI
            TheFinalCallSettings.Instance.LogSettings();

            // Update the current WoWContext, and fire an event for the change.
            UpdateContext();

            // NOTE: Hook these events AFTER the context update.
            OnWoWContextChanged += (orig, ne) =>
                {
                    Logger.Write(Color.White, "Context changed, re-creating behaviors");
                    RebuildBehaviors();
                };
            RoutineManager.Reloaded += (s, e) =>
                {
                    Logger.Write(Color.White, "Routines were reloaded, re-creating behaviors");
                    RebuildBehaviors();
                };

            // create silently since will creating again right after this
            if (!RebuildBehaviors(true))
            {
                return;
            }
            Logger.WriteDebug(Color.White, "Verified behaviors can be created!");

            // When we actually need to use it, we will.
            EventHandlers.Init();
            MountManager.Init();
            HotkeyManager.Init();
            MovementManager.Init();
            SoulstoneManager.Init();

            //Logger.Write("Combat log event handler started.");

            // create silently since Start button will create a context change (at least first Start)
            // .. which will build behaviors again
            Instance.RebuildBehaviors(true);

            Logger.Write("Initialization complete!");
        }

        public static Version GetTheFinalCallVersion()
        {
            return new Version("1.0.0.1");
        }

        private static void WriteSupportInfo()
        {
            string TheFinalCallName = "TheFinalCall v" + GetTheFinalCallVersion();
            Logger.Write("Starting " + TheFinalCallName);

            // save some support info in case we need
            Logger.WriteFile("{0:F1} days since Windows was restarted",
                             TimeSpan.FromMilliseconds(Environment.TickCount).TotalHours/24.0);
            Logger.WriteFile("{0} FPS currently in WOW", GetFPS());
            Logger.WriteFile("{0} ms of Latency in WOW", StyxWoW.WoWClient.Latency);
            Logger.WriteFile("{0} local system time", DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss"));
        }

        private static void StopBot(string reason)
        {
            Logger.Write(reason);
            TreeRoot.Stop();
        }

        private static uint GetFPS()
        {
            try
            {
                return (uint) Lua.GetReturnVal<float>("return GetFramerate()", 0);
            }
            catch
            {
            }

            return 0;
        }
    }
}